package ms.jacrim.framework;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ms.jacrim.framework.SolutionManager.ActionStatus;
import ms.jacrim.pddl.PddlSolution;

public class ActiveSolution implements Serializable {
	private static final long serialVersionUID = 1L;
	
	private PddlSolution pddlsolution;

	public class ActionInfo implements Serializable {
		private static final long serialVersionUID = 1L;
		public final PddlSolution.Action Action;
		private ActionStatus status = ActionStatus.PENDING;
		private Date start, end, fail;

		public ActionInfo(PddlSolution.Action action) {
			Action = action;
		}

		public ActionStatus getStatus() {
			return status;
		}

		public void setStatus(ActionStatus status) {
			this.status = status;
			if (status == ActionStatus.ACCOMPLISHED)
				end = new Date();
			else if (status == ActionStatus.EXECUTING)
				start = new Date();
			else if (status == ActionStatus.FAIL)
				fail = new Date();
		}

		public Date getStart() {
			return start != null ? start : end;
		}

		public Date getEnd() {
			return end;
		}
		
		public Date getFail() {
			return fail;
		}
		
		@Override
		public String toString() {
			String result;
			SimpleDateFormat df = new SimpleDateFormat("yyyyMMddhhmmss");
			switch (status) {
			case ACCOMPLISHED:
				result = String.format("accomplished,s[%s],e[%s]", df.format(getStart()), df.format(getEnd()));
				break;
			case EXECUTING:
				result = String.format("executing,s[%s]", df.format(getStart()));
				break;
			case FAIL:
				result = String.format("fail");
				break;
			default:
				result = "pending";
			}
			return result;
		}

		public String getTitle() {
			String act = Action.Name().toLowerCase();
			switch (Action.getFunctor()) {
			case PASSES:
				act = end != null ? "passed" : "is passing";
				break;
			case SATISFIES:
				act = end != null ? "fulfilled" : "is fulfilling";
				break;
			}
			return String.format("%s %s %s", Action.Argument(0), act, Action.Argument(1));
		}
	}

	private Map<PddlSolution.Action, ActionInfo> actInfo = new HashMap<PddlSolution.Action, ActionInfo>();

	public int ActionCount() {
		return pddlsolution.ActionCount();
	}

	public PddlSolution.Action getAction(int idx) {
		return pddlsolution.getAction(idx);
	}

	protected void setSolution(PddlSolution sol) {
		pddlsolution = sol;
		actInfo.clear();
	}

	public PddlSolution.Action findAction(String functor) {
		for (int idx = 0; idx < pddlsolution.ActionCount(); idx ++) {
			PddlSolution.Action a = getAction(idx);
			if (a.toString().equalsIgnoreCase(functor))
				return a;
		}
		return null;
	}
	
	public PddlSolution.Action findAction(String functor, String... args) {
		for (int idx = 0; idx < pddlsolution.ActionCount(); idx++) {
			PddlSolution.Action a = getAction(idx);
			if (a.Name().equalsIgnoreCase(functor) && args.length == a.ArgumentCount()) {
				boolean success = true;
				for (int j = 0; j < args.length && (success = args[j].equalsIgnoreCase(a.Argument(j))); j++)
					;
				if (success)
					return a;
			}
		}
		return null;
	}

	public ActionInfo findActionInfo(PddlSolution.Action action) {
		return actInfo.get(action);
	}
	
	public synchronized ActionInfo getActionInfo(PddlSolution.Action action) {
		ActionInfo ai = actInfo.get(action);
		if (ai == null)
			actInfo.put(action, ai = new ActionInfo(action));
		return ai;
	}

	public ActionInfo getActionInfo(String functor) {
		PddlSolution.Action act = findAction(functor);
		return act != null ? getActionInfo(act) : null;
	}
	
	public ActionInfo getActionInfo(String functor, String... args) {
		PddlSolution.Action act = findAction(functor, args);
		return act != null ? getActionInfo(act) : null;
	}
	
	public Collection<ActionInfo> getActionInfos() {
		return actInfo.values();
	}

	public boolean Available() {
		return pddlsolution != null;
	}

	
	public List<PddlSolution.Action> toArray() {
		return pddlsolution.toArray();
	}
}